#include "StdAfx.h"
#include "HttpUtility.h"
#include "VideoAnalyser.h"

CVideoAnalyser::~CVideoAnalyser()
{
}

void CVideoAnalyser::__AddVideo(LPCTSTR url)
{
	TReferer* pref;
	CString referer;
	if (!mRefererUnmap.Lookup(url, referer))
		referer = url;
	if (!mRefererMap.Lookup(referer, pref))
	{
		mRefererMap.SetAt(referer, pref = new TReferer());
		pref->pos = NULL;
		pref->isVideo = true;
		OnVideo(referer);
		TRACE(_T("%s\n"), (LPCTSTR)referer);
	}
	else if (!pref->isVideo)
	{
		pref->isVideo = true;
		mRefererList.RemoveAt(pref->pos);
		pref->pos = NULL;
	}
}

void CVideoAnalyser::CHttpSession::OnTCPSend(const u_char* data, u_long offset, u_long size)
{
	if (request)
	{
		const char* p = (const char*)data + requestBegin;
		int n = offset + size - requestBegin;
		ParseHttp(p, n);
	}
}

void CVideoAnalyser::CHttpSession::OnTCPReceive(const u_char* data, u_long offset, u_long size)
{
	if (!request)
	{
		const char* p = (const char*)data + responseBegin;
		int n = offset + size - responseBegin;
		ParseHttp(p, n);
	}
}

void CVideoAnalyser::CHttpSession::ParseHttp(const char* p, int n)
{
	if (!request)
		TRACE(_T("Response %u %s\n"), n, (LPCTSTR)url);
	if (!header)
		header = HttpUtility::GetHttpHeaderLength(p, n);
	if (header)
	{
		if (request)
		{
			if (url.IsEmpty())
			{
				url = HttpUtility::GetHttpRequestURL(p, header, socket.dest.addr, socket.dest.port);
				TRACE(_T("%s\n"), (LPCTSTR)url);
			}
			int l = HttpUtility::GetHttpRequestLength(p, n, header);
			if (l) // if Request end
			{
				requestBegin += l;
				request = false;
				header = false;
				m3u8 = false;
				location.Empty();
				contentType.Empty();
				contentEncoding.Empty();
				statusCode = 0;
			}
		}
		else
		{
			const char* value;
			int valuelen;
			if (!statusCode)
			{
				statusCode = HttpUtility::GetHttpResponseStatusCode(p);
				TRACE(_T("Status: %u\n"), statusCode);
			}
			if (statusCode)
			{
				if (statusCode / 100 == 3)
				{
					if (location.IsEmpty() && HttpUtility::GetHttpHeader(p, header, "Location", value, valuelen))
					{
						location = CString(value, valuelen);
						TRACE(_T("Location: %s\n"), location);
						TReferer* pref;
						CString referer;
						if (container->mRefererUnmap.Lookup(url, referer))
						{
							container->mRefererMap.Lookup(referer, pref);
						}
						else
						{
							referer = url;
							if (!container->mRefererMap.Lookup(referer, pref))
							{
								container->mRefererMap.SetAt(referer, pref = new TReferer());
								pref->pos = container->mRefererList.AddTail(referer);
								pref->isVideo = false;
							}
						}
						container->mRefererUnmap.SetAt(location, referer);
						pref->urls.AddTail(location);
					}
				}
				else if (statusCode / 100 == 2)
				{
					if (contentType.IsEmpty() && HttpUtility::GetHttpHeader(p, header, "Content-Type", value, valuelen))
					{
						contentType = CString(value, valuelen);
						TRACE(_T("Content-Type: %s\n"), contentType);
						if (_strnicmp(value, "video/", 6) == 0) // if Video
							container->__AddVideo(url);
					}
				}
			}
			if (statusCode / 100 == 2)
			{
				if (contentEncoding.IsEmpty())
				{
					if (HttpUtility::GetHttpHeader(p, header, "Content-Encoding", value, valuelen))
						contentEncoding = CString(value, valuelen);
					else
						contentEncoding = _T("____");
					TRACE(_T("Content-Encoding: %s\n"), contentEncoding);
				}
				if (!contentEncoding.IsEmpty())
				{
					u_char t[128], data[8];
					int size;
					if (contentEncoding.CompareNoCase(_T("gzip")) == 0 && n - header > sizeof(t))
					{
						size = HttpUtility::GetHttpResponseData(t, sizeof(t), p, n, header, chunked);
						size = HttpUtility::gzipDecode(t, size, data, sizeof(data));
					}
					else if (n - header > sizeof(data))
					{
						size = HttpUtility::GetHttpResponseData(data, sizeof(data), p, n, header, chunked);
					}
					if (size >= sizeof(data))
					{
						if (memcmp(data, "#EXTM3U", 7) == 0) // if m3u8
						{
							container->__AddVideo(url);
							m3u8 = true;
						}
						else if (memcmp(data, "FLV", 3) == 0) // if Video
						{
							container->__AddVideo(url);
						}
					}
				}
			}
			int l = HttpUtility::GetHttpResponseLength(p, n, header, false, chunked, contentLength);
			if (l) // if Response end
			{
				if (m3u8)
				{
					CArray<char, char> data;
					int size = n - header;
					if (contentEncoding.CompareNoCase(_T("gzip")) == 0)
					{
						CArray<u_char, u_char> t;
						t.SetSize(size);
						size = HttpUtility::GetHttpResponseData(t.GetData(), size, p, n, header, chunked);
						data.SetSize(size << 2);
						size = HttpUtility::gzipDecode(t.GetData(), size, (u_char*)data.GetData(), data.GetSize());
					}
					else if (n - header > sizeof(data))
					{
						data.SetSize(size);
						size = HttpUtility::GetHttpResponseData((u_char*)data.GetData(), size, p, n, header, chunked);
					}
					size = size;
				}
				responseBegin += l;
				request = true;
				url.Empty();
				header = chunked = false;
			}
		}
	}
}
